package org.stan.beanvalidator.utils;

import org.stan.beanvalidator.annotation.*;
import org.stan.beanvalidator.annotation.Number;
import org.stan.beanvalidator.bean.PatternField;
import org.stan.beanvalidator.deletage.CHNPostCodeValidator;
import org.stan.beanvalidator.deletage.DeletageAdapter;
import org.stan.beanvalidator.deletage.IPostCodeDeletage;
import org.stan.beanvalidator.factory.BeanValidateSingletonFactory;
import org.stan.beanvalidator.bean.ValidateMsg;
import org.apache.commons.lang3.StringUtils;
import org.stan.beanvalidator.bean.ValidateResult;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Set;

/**
 * 工厂校验器工具类
 * @author src
 * @Date 2020/6/9 12:34
 * @version 1.0
 */
public class ValidatorUtil {
    /**
     * 获取属性值
     * @author src
     * @Date 2020/6/8 15:44
     * @version 1.0
     */
    public static Object getValue(Field field, Object bean) throws Exception{
        // 暴力访问
        field.setAccessible(true);
        // 获取属性类型
        Class<?> type = field.getType();
        System.out.println("字段 = [" + field.getName() + "]类型为："+type);
        // 获取属性值
        Object value = field.get(bean);
        // 如果属性类型为String
        if (type==String.class&&value!=null){
            value=value.toString().trim();  // 去掉前后空格
        }
        return value;
    }

    /**
     * 属性值为空时
     * @author src
     * @Date 2020/6/8 16:13
     * @version 1.0
     */
    public static void fieldValueIsNull(Field field){
        // 添加到校验失败集合
        ValidateMsg msg = new ValidateMsg();
        msg.setField(field.getName());
        msg.setMsg("属性["+ field.getName() +"]不能为空!");
        BeanValidateSingletonFactory.getInstance().addFaileList(msg);
    }

    /**
     *@Description 检查是否有新的校验方式
     *@Author src
     *@Date 2020-06-13 15:12
     *@Param
     *@return
     */
    public static boolean isContains(Field field,Set<PatternField> patternFields){
        boolean flag=false;
        for (PatternField patternField : patternFields) {
            if(StringUtils.equals(patternField.getFieldName(),field.getName())){
                flag=true;
                break;
            }
        }
        return flag;
    }

    /**
     *@Description 对比是否有新的校验格式
     *@Author src
     *@Date 2020-06-13 14:52
     *@Param
     *@return
     */
    public static void validateNew(Field field, Object bean, Set<PatternField> patternFields)throws Exception{
        // 当前字段没有新的校验方式，照原来的校验方式校验
        // 有新的校验方式，按新的格式校验
        for (PatternField patternField : patternFields) {
            if(!StringUtils.equals(patternField.getFieldName(),field.getName())){continue;}
            patternNew(field,bean,patternField);
        }
    }


    /**
     *@Description 新的校验格式
     *@Author src
     *@Date 2020-06-13 14:42
     *@Param
     *@return
     */
    private static void patternNew(Field field, Object bean, PatternField patternField)throws Exception{
        Object value = ValidatorUtil.getValue(field,bean);
        checkPattern(field,value,patternField);
    }

    /**
     * 首字母转大写
     * @author src
     * @Date 2020/6/19 16:31
     * @version 1.0
     */
    public static String upperCase(String str) {
        char[] ch = str.toCharArray();
        if (ch[0] >= 'a' && ch[0] <= 'z') {
            ch[0] = (char) (ch[0] - 32);
        }
        return new String(ch);
    }

    /**
     *@Description 获取基于注解的值
     *@Author src
     *@Date 2020-06-21 15:52
     *@Param
     *@return
     */
    public static Object getAspectValue(Field field,Class<?> clazz,Object bean)throws Exception{
        // 暴力访问
        field.setAccessible(true);
        // 获取属性类型，基本数据类型 int、boolean有默认值
        Class<?> type = field.getType();
        String methodPrefix;
        if (type == boolean.class) {
            methodPrefix = "is";
        } else {
            methodPrefix = "get";
        }
        Method m = clazz.getMethod(methodPrefix + ValidatorUtil.upperCase(field.getName()));
        return m.invoke(bean);
    }

    /**
     *@Description 校验自定义正则是否正确
     *@Author src
     *@Date 2020-06-21 17:44
     *@Param
     *@return
     */
    public static void checkPattern(Field field, Object value, PatternField patternField){
        if (PatternUtil.isEmpty(value)){
            ValidatorUtil.fieldValueIsNull(field);
            return;
        }

        if(StringUtils.isEmpty(patternField.getRegx())){
            ValidateMsg msg = new ValidateMsg();
            msg.setField(field.getName());
            msg.setMsg("正则表达式不能为空！");
            BeanValidateSingletonFactory.getInstance().addFaileList(msg);
            return;
        }

        if (!PatternUtil.pattern(patternField.getRegx(),value.toString())){
            ValidateMsg msg = new ValidateMsg();
            msg.setField(field.getName());
            msg.setMsg(patternField.getMsg());
            BeanValidateSingletonFactory.getInstance().addFaileList(msg);
            return;
        }
    }

    /**
     *@Description 身份证校验
     *@Author src
     *@Date 2020-06-21 19:08
     *@Param
     *@return
     */
    public static void validateIDCard(Object value, Field field){
        if(!PatternUtil.isEmpty(value)){
            PatternResult result = PatternUtil.regexIDCard(value.toString());
            if (!result.isResult()){
                IDCard idCard = field.getAnnotation(IDCard.class);
                // 添加到校验失败集合
                ValidateMsg msg = new ValidateMsg();
                msg.setField(field.getName());
                msg.setFieldName(idCard.name());
                msg.setMsg(idCard.msg()+result.getMsg());
                BeanValidateSingletonFactory.getInstance().addFaileList(msg);
            }
        }else {
            ValidatorUtil.fieldValueIsNull(field);
        }
    }

    /**
     *@Description 邮箱格式校验
     *@Author src
     *@Date 2020-06-21 19:30
     *@Param
     *@return
     */
    public static void validateEmail(Object value, Field field){
        if (!PatternUtil.isEmpty(value)){
            if (!PatternUtil.patternEmail(value.toString())){
                Email email = field.getAnnotation(Email.class);
                // 添加到校验失败集合
                ValidateMsg msg = new ValidateMsg();
                msg.setField(field.getName());
                msg.setFieldName(email.name());
                msg.setMsg(email.msg());
                BeanValidateSingletonFactory.getInstance().addFaileList(msg);
            }
        }else{
            ValidatorUtil.fieldValueIsNull(field);
        }
    }

    /**
     *@Description 校验固定电话
     *@Author src
     *@Date 2020-06-21 20:33
     *@Param
     *@return
     */
    public static void validateTel(Object value, Field field){
        if (!PatternUtil.isEmpty(value)){
            if (!PatternUtil.pattenTel(value.toString())){
                Tel tel = field.getAnnotation(Tel.class);
                // 添加到校验失败集合
                ValidateMsg msg = new ValidateMsg();
                msg.setField(field.getName());
                msg.setFieldName(tel.name());
                msg.setMsg(tel.msg());
                BeanValidateSingletonFactory.getInstance().addFaileList(msg);
            }
        }else{
            ValidatorUtil.fieldValueIsNull(field);
        }
    }

    /**
     *@Description 校验手机号
     *@Author src
     *@Date 2020-06-21 20:41
     *@Param
     *@return
     */
    public static void validateMobile(Object value, Field field){
        if (!PatternUtil.isEmpty(value)){
            if (!PatternUtil.patternMobile(value.toString())){
                Mobile mobile = field.getAnnotation(Mobile.class);
                // 添加到校验失败集合
                ValidateMsg msg = new ValidateMsg();
                msg.setField(field.getName());
                msg.setFieldName(mobile.name());
                msg.setMsg(mobile.msg());
                BeanValidateSingletonFactory.getInstance().addFaileList(msg);
            }
        }else{
            ValidatorUtil.fieldValueIsNull(field);
        }
    }

    /**
     *@Description 数字校验器
     *@Author src
     *@Date 2020-06-21 20:54
     *@Param 
     *@return 
     */
    public static void validateNumber(Object value, Field field) {
        if (!PatternUtil.isEmpty(value)){
            if (!PatternUtil.patternNumber(value.toString())){
                Number number = field.getAnnotation(Number.class);
                // 添加到校验失败集合
                ValidateMsg msg = new ValidateMsg();
                msg.setField(field.getName());
                msg.setFieldName(number.name());
                msg.setMsg(number.msg());
                BeanValidateSingletonFactory.getInstance().addFaileList(msg);
            }
        }else{
            ValidatorUtil.fieldValueIsNull(field);
        }
    }

    /**
     *@Description 自定义校验器
     *@Author src
     *@Date 2020-06-21 20:59
     *@Param
     *@return
     */
    public static void validatePattern(Object value, Field field) {
        if (!PatternUtil.isEmpty(value)){
            Pattern pattern = field.getAnnotation(Pattern.class);
            if(PatternUtil.isEmpty(pattern.ex())){
                // 添加到校验失败集合
                ValidateMsg msg = new ValidateMsg();
                msg.setField(field.getName());
                msg.setFieldName(pattern.name());
                msg.setMsg("请填写bean中ex正则表达式");
                BeanValidateSingletonFactory.getInstance().addFaileList(msg);
                return;
            }
            if (!PatternUtil.pattern(pattern.ex(),value.toString())){
                // 添加到校验失败集合
                ValidateMsg msg = new ValidateMsg();
                msg.setField(field.getName());
                msg.setFieldName(pattern.name());
                msg.setMsg(pattern.msg());
                BeanValidateSingletonFactory.getInstance().addFaileList(msg);
            }
        }else{
            ValidatorUtil.fieldValueIsNull(field);
        }
    }

    /**
     *@Description 非空校验
     *@Author src
     *@Date 2020-06-21 21:04
     *@Param
     *@return
     */
    public static void validateNotEmpty(Object value, Field field){
        // 校验非空
        if(PatternUtil.isEmpty(value)){
            NotEmpty notEmpty = field.getAnnotation(NotEmpty.class);
            // 添加到校验失败集合
            ValidateMsg msg = new ValidateMsg();
            msg.setField(field.getName());
            msg.setFieldName(notEmpty.name());
            msg.setMsg(notEmpty.msg());
            BeanValidateSingletonFactory.getInstance().addFaileList(msg);
        }
    }

    /**
     *@Description 邮编校验器
     *@Author src
     *@Date 2020-07-12 10:10
     *@Param
     *@return
     */
    public static void validatePostCode(Object value, Field field) {
        if (!PatternUtil.isEmpty(value)){
            PostCode postCode = field.getAnnotation(PostCode.class);
            if(getPostCodeArea(postCode.area())==null){
                System.out.println("对不起，暂不支持地区为【"+ postCode.area() +"】的邮编校验规则！本字段将不校验！");
                return;
            }
            // 委派模式
            DeletageAdapter adapter = new DeletageAdapter(getPostCodeArea(postCode.area()));
            boolean flag = adapter.validatePostCode(value.toString());
            if (!flag){
                // 添加到校验失败集合
                ValidateMsg msg = new ValidateMsg();
                msg.setField(field.getName());
                msg.setFieldName(postCode.name());
                msg.setMsg(postCode.msg());
                BeanValidateSingletonFactory.getInstance().addFaileList(msg);
            }
        }else{
            ValidatorUtil.fieldValueIsNull(field);
        }
    }

    /**
     *@Description 根据邮编区域找到具体的邮编执行者（策略模式）
     *@Author src
     *@Date 2020-07-12 11:20
     *@Param
     *@return
     */
    private static IPostCodeDeletage getPostCodeArea(String area) {
        // 国家地区编码：使用三位国际标准国家地区代码--ISO 3166-1 去除前后空格转大写
        return BeanValidateSingletonFactory.getInstance().getDeletageMap().get(area.trim().toUpperCase());
    }


    /**
     * 返回注解类型name
     * @author src
     * @Date 2020/6/29 9:27
     * @version 1.0
     */
    public static String getAnnotation(Field field) {
        if(field.isAnnotationPresent(NotEmpty.class)){
            // 非空校验器
            return ValidateConstant.NotEmpty;
        }else if(field.isAnnotationPresent(IDCard.class)){
            // 身份证校验器
            return ValidateConstant.IDCard;
        }else if(field.isAnnotationPresent(Email.class)){
            // 邮箱校验器
            return ValidateConstant.Email;
        }else if(field.isAnnotationPresent(Tel.class)){
            // 座机号码校验器
            return ValidateConstant.Tel;
        }else if(field.isAnnotationPresent(Mobile.class)){
            // 手机号码校验器
            return ValidateConstant.Mobile;
        }else if(field.isAnnotationPresent(Pattern.class)){
            // 自定义校验器
            return ValidateConstant.Pattern;
        }else if(field.isAnnotationPresent(Number.class)) {
            // 数字验证器
            return ValidateConstant.Number;
        }else if(field.isAnnotationPresent(PostCode.class)){
            // 邮编校验器
            return ValidateConstant.PostCode;
        }else{
            return ValidateConstant.Default_Factory;
        }
    }

    /**
     * 重置校验结果,保证每次校验都是初始化状态
     * @author src
     * @Date 2020/6/29 10:02
     * @version 1.0
     */
    public static void refreshResult(){
        BeanValidateSingletonFactory.getInstance().refreshFaileList();
    }

    /**
     * 获取最新的校验结果
     * @author src
     * @Date 2020/6/29 10:06
     * @version 1.0
     */
    public static ValidateResult getValidateResult(){
        // 单例实现
        return BeanValidateSingletonFactory.getInstance().getValidateResult();
    }

    /**
     *@Description 注解校验
     *@Author src
     *@Date 2020-06-21 19:13
     *@Param
     *@return
     */
    public static void validateAnnotation(BeanValidate beanValidate, Field field, Object bean, Class<?> clazz)throws Exception{
        // 不校验集合
        String[] ex = null;
        if (StringUtils.isNotEmpty(beanValidate.excludes())){
            ex = beanValidate.excludes().split("\\|");
        }

        // 添加新的校验属性，如果原来已经有校验方式，则按新的进行
        String[] pt = null;
        if (StringUtils.isNotEmpty(beanValidate.addPattern())){
            pt = beanValidate.addPattern().split("\\|");
        }
        // 排除不校验的属性
        if(null!=ex&&ex.length>0&&beanValidate.excludes().contains(field.getName())){
            // 如果新规则中又添加了被排除的属性，则按新规则执行
            if(!(null!=pt&&pt.length>0&&beanValidate.addPattern().contains(field.getName()))){ return; }
            // 按照新规则执行
            validateNew(field,bean,clazz,pt);
            return;
        }
        // 如果不排除该属性，则判断是否有新规则
        if(null!=pt&&pt.length>0&&beanValidate.addPattern().contains(field.getName())){
            validateNew(field,bean,clazz,pt);
            return;
        }
    }

    /**
     *@Description 重载，基于注解-新校验规则
     *@Author src
     *@Date 2020-06-21 17:39
     *@Param
     *@return
     */
    private static void validateNew(Field field, Object bean, Class<?> clazz, String[] pt)throws Exception{
        for (String s : pt) {
            String[] p = s.split(";");
            if(p.length<3){
                ValidateMsg msg = new ValidateMsg();
                msg.setField(field.getName());
                msg.setMsg("自定义注解BeanValidate.addPattern()参数有误！");
                BeanValidateSingletonFactory.getInstance().addFaileList(msg);
                continue;
            }
            /** name;ex;msg **/
            if(!StringUtils.equals(p[0],field.getName())){continue;}
            PatternField patternField = new PatternField();
            patternField.setFieldName(p[0]);
            patternField.setRegx(p[1]);
            patternField.setMsg(p[2]);
            ValidatorUtil.checkPattern(field,ValidatorUtil.getAspectValue(field,clazz,bean),patternField);
        }
    }


}
